﻿namespace Knownet.BNF.Inline
{
  using System;
  using System.Text;
  using System.Collections;
  using Knownet.AST;

  /// <summary>
  /// BNF的定义项。
  /// 定义项包含若干字句。
  /// </summary>
  /// <remarks>
  /// 
  /// 使用N，T，R等符号（内置函数）以及*，+等操作符生成的
  /// BNF等价语法，成为简化内联语法。
  /// 
  /// 简化内联语法提供代码层次上的BNF书写能力。
  /// 这将辅助程序员用较少的代码或者避免使用外部
  /// 书写BNF而直接实现一些基本的语法定义和分析功能。
  /// 简化内联语法可以如下定义：
  /// 
  /// public class TestBnf : BnfDefinition
  /// {
  ///   public TestBnf(): base
  ///   (
  ///      N("a") * N("b")++
  ///      +
  ///      N("c")
  ///      +
  ///      T("d") * N("k")
  ///   ) { }
  ///   public virtual void TestIt()
  ///   {
  ///   }
  /// }
  /// 也可以通过重载OnInitializedefinition实现定义。
  /// 
  /// 两种方法的不同在于，构造函数中的定义
  /// 可能无法支持语义动作挂接。
  /// 而OnInitializedefinition
  /// 中可以实现语义动作的挂接。
  /// 
  /// 此外，由源代码打印机自动生成的源代码将使用
  /// 这种语法实现BNF的内联。有了源码打印机的支持，
  /// 我们可以从手工书写的BNF直接生成上述形式的
  /// BNF定义类的派生类。进而实现AST的自动生成。
  /// 
  /// </remarks>
  public class BnfDefinition : SyntaxNode
  {
    #region Consts
    /// <summary>
    /// 子句选择符号，用于生成简单内联语法。
    /// </summary>
    public const string SelectionSign = "+";
    /// <summary>
    /// 缩进空格。
    /// </summary>
    public const char IdentSpace = ' ';
    #endregion
    #region Statics
    #region Shortcuts
    /// <summary>
    /// 创建签名为primitiveSignature的Primitive封装。
    /// </summary>
    public static BnfDefinition wrap(string primitiveSignature)
    {
      return BnfDefinition.accordingTo(BnfPrimitive.of(primitiveSignature));
    }
    /// <summary>
    /// 创建指定定义的对等物。
    /// </summary>
    public static BnfDefinition accordingTo(BnfDefinition definition)
    {
      return new BnfDefinition(definition);
    }
    /// <summary>
    /// 创建具有指定签名和子句定义列表的BnfDefinition定义。
    /// </summary>
    /// <param name="signature"></param>
    /// <param name="clauses"></param>
    /// <returns></returns>
    public static BnfDefinition accordingTo(string signature, params BnfClause[] clauses)
    {
      return new BnfDefinition(signature, clauses);
    }
    /// <summary>
    /// 创建BnfPrimitive非终结符。
    /// </summary>
    /// <remarks>
    /// 这是简单内联语法。
    /// </remarks>
    public static BnfPrimitive N(string signature)
    {
      BnfPrimitive p = BnfPrimitive.of(signature);
      p.IsLiteral = false;
      p.IsReference = false;
      return p;
    }
    /// <summary>
    /// 创建BnfPrimitive非终结符。
    /// </summary>
    /// <remarks>
    /// 这是简单内联语法。
    /// </remarks>
    public static BnfPrimitive N(string signature, bool optional, bool repeatable)
    {
      BnfPrimitive p = N(signature);
      p.IsOptional = optional;
      p.IsRepeatable = repeatable;
      return p;
    }
    /// <summary>
    /// 创建BnfPrimitive终结符。
    /// </summary>
    /// <remarks>
    /// 这是简单内联语法。
    /// </remarks>
    public static BnfPrimitive T(string signature)
    {
      BnfPrimitive p = BnfPrimitive.of(signature);
      p.IsLiteral = true;
      return p;
    }
    /// <summary>
    /// 创建BnfPrimitive终结符。
    /// </summary>
    /// <remarks>
    /// 这是简单内联语法。
    /// </remarks>
    public static BnfPrimitive T(string signature, bool optional, bool repeatable)
    {
      BnfPrimitive p = T(signature);
      p.IsOptional = optional;
      p.IsRepeatable = repeatable;
      return p;
    }
    /// <summary>
    /// 创建BnfPrimitive引用。
    /// </summary>
    /// <remarks>
    /// 这是简单内联语法。
    /// </remarks>
    public static BnfPrimitive R(string signature)
    {
      BnfPrimitive p = BnfPrimitive.of(signature);
      p.IsReference = true;
      return p;
    }
    /// <summary>
    /// 创建BnfPrimitive引用。
    /// </summary>
    /// <remarks>
    /// 这是简单内联语法。
    /// </remarks>
    public static BnfPrimitive R(string signature, bool optional, bool repeatable)
    {
      BnfPrimitive p = R(signature);
      p.IsOptional = optional;
      p.IsRepeatable = repeatable;
      return p;
    }
    /// <summary>
    /// 创建缺省的定义实例。
    /// </summary>
    public static new BnfDefinition CreateInstance()
    {
      return new BnfDefinition();
    }
    #endregion
    #region Operators
    /// <summary>
    /// 子句选择操作符重载。
    /// </summary>
    public static BnfDefinition operator +(BnfDefinition def, BnfPrimitive primitive)
    {
      if (def != null)
      {
        return def.Combine((BnfClause)primitive);
      }
      return def;
    }
    /// <summary>
    /// 子句选择操作符重载。
    /// </summary>
    public static BnfDefinition operator +(BnfDefinition def, BnfClause clause)
    {
      if (def != null)
      {
        return def.Combine(clause);
      }
      return def;
    }
    /// <summary>
    /// 名称关联操作符重载。
    /// </summary>
    /// <remarks>
    /// 此操作符可以将左侧的名称关联到
    /// 右侧的BnfDefinition定义上。
    /// </remarks>
    public static BnfDefinition operator &(string name, BnfDefinition rightDef)
    {
      if (rightDef == null && name != null)
      {
        rightDef.NamingAs(name);
      }
      return rightDef;
    }
    #endregion
    #endregion
    #region Properties
    /// <summary>
    /// 判别当前定义是否是终结符等价的。
    /// </summary>
    /// <remarks>
    /// 如果当前定义中的所有子句都是
    /// 终结符封装（IsTerminalWrapper）
    /// 那么当前定义就是终结符等价的。
    /// </remarks>
    public virtual bool IsTerminalEquivalent
    {
      get
      {
        if (this.HasContainingNodes)
        {
          foreach (BnfClause clause in this.ContainingNodes)
          {
            if (!clause.IsTerminalWrapper)
            {
              return false;
            }
          }
        }
        return true;
      }
    }
    public virtual bool IsReferenceEquivalent
    {
      get
      {
        if (this.HasContainingNodes)
        {
          foreach (BnfClause clause in this.ContainingNodes)
          {
            if (!clause.IsReferenceWrapper)
            {
              return false;
            }
          }
        }
        return true;
      }
    }
    /// <summary>
    /// 判别当前定义是否是归纳的。
    /// </summary>
    /// <remarks>
    /// 如果当前定义的所有子句都只具有
    /// 一个BnfPrimitive，那么当前定义
    /// 就是归纳的。
    /// </remarks>
    public virtual bool IsInductive
    {
      get
      {
        if (this.HasContainingNodes)
        {
          foreach (BnfClause clause in this.ContainingNodes)
          {
            if (clause.ContainingNodes.Count > 1)
            {
              return false;
            }
          }
        }
        return true;
      }
    }
    /// <summary>
    /// 获取当前定义中的子句列表。
    /// 为了便于处理，单一Primitive
    /// 也被封装在子句之中，所以
    /// 定义只包含子句。
    /// </summary>
    public virtual IList Clauses
    {
      get
      {
        return this.ContainingNodes;
      }
    }
    #endregion
    #region Constructors
    public BnfDefinition()
      : base()
    {
      this.DefineAs(this.OnInitializedefinition());
    }
    public BnfDefinition(BnfDefinition definition)
      : base()
    {
      this.DefineAs(definition);
    }
    public BnfDefinition(string signature, params BnfClause[] clauses)
      : base(signature,null,null, clauses)
    {

    }
    #endregion
    #region Methods
    /// <summary>
    /// 当前定义被设定为和指定的定义相等价。
    /// </summary>
    public virtual BnfDefinition DefineAs(BnfDefinition definition)
    {
      if (definition != null)
      {
        this.NamingAs(
            (
              string.IsNullOrEmpty(definition.Signature)
            ) ?
            this.GetTypeName() :
            definition.Signature
          );

        this.ContainingNodes.AddRange(definition.ContainingNodes);
      }
      return definition;
    }
    /// <summary>
    /// 将子句复合到定义之中。
    /// </summary>
    public virtual BnfDefinition Combine(params BnfClause[] clauses)
    {
      return this.Combine(clauses as ICollection);
    }
    /// <summary>
    /// 将子句复合到定义之中。
    /// </summary>
    public virtual BnfDefinition Combine(ICollection clauses)
    {
      if (clauses != null)
      {
        foreach (BnfClause clause in clauses)
        {
          this.AddContainingNodes(clause);
        }
      }
      return this;
    }
    /// <summary>
    /// 将当前定义命名为指定名称。
    /// </summary>
    public virtual BnfDefinition NamingAs(string signature)
    {
      this.signature = signature;
      return this;
    }
    /// <summary>
    /// Bnfdefinition的缺省构造将调用此方法
    /// 以实现定义的初始化。
    /// </summary>
    /// <returns>Bnfdefinition定义。缺省为空。</returns>
    protected virtual BnfDefinition OnInitializedefinition()
    {
      return null;
    }
    /// <summary>
    /// 缺省的动作处理方法。
    /// </summary>
    /// <remarks>
    /// 派生类可重载此方法，
    /// 或者自行定义方法以实现
    /// 语义动作的处理。
    /// </remarks>
    protected virtual void DefaultActionHandler(SyntaxNode currentSymbol)
    {

    }
    /// <summary>
    /// 获取当前类型的名称，此名称可以用于当前定义的签名。
    /// </summary>
    protected virtual string GetTypeName()
    {
      return this.GetType().Name;
    }
    /// <summary>
    /// 生成当前定义的简单内联语法。
    /// </summary>
    /// <param name="ident">缩进的字符数量。</param>
    public virtual string ToString(int ident)
    {
      StringBuilder builder = new StringBuilder();
      if (this.HasContainingNodes)
      {
        for (int i = 0; i < this.ContainingNodes.Count; i++)
        {
          if (ident >= 0)
          {
            builder.Append(IdentSpace, ident);
          }
          builder.AppendLine(this.ContainingNodes[i].ToString());
          if (i != this.ContainingNodes.Count - 1)
          {
            if (ident >= 0)
            {
              builder.Append(IdentSpace, ident);
            }
            builder.AppendLine(SelectionSign);
          }
        }
      }
      return builder.ToString();
    }
    #endregion
  }
}
